/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.colswe.solestac.control;

import java.io.IOException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import org.colswe.solestac.VO.RequestVO;
import org.colswe.solestac.VO.StudentVO;
import org.colswe.solestac.dao.InstanceDao;
import org.colswe.solestac.dao.RequestDao;
import org.colswe.solestac.dao.StudentDao;
import org.colswe.solestac.dao.RequestTypeDao;
import org.colswe.solestac.dao.ProgramDao;
import org.colswe.solestac.entity.Student;
import org.colswe.solestac.entity.Request;
import org.colswe.solestac.entity.RequestType;
import org.colswe.solestac.entity.Instance;

/**
 *
 * @author Edison Parra
 * @version 1.1
 * @since Abril 14 de 2012
 */
public class RequestControl {
    
    /**
     * ALL GOOD = 0.
     */
    public static final int ALL_GOOD = 0;
    /**
     * INVALID PERIOD NAME = -6.
     */
    public static final int INVALID_PERIOD_NAME = -6;
    /**
     * NO DECICION = -3.
     */
    public static final int NO_DECICION = -3;
    /**
     * NO INSTANCE = -2.
     */
    public static final int NO_INSTANCE = -2;
    /**
     * NO PERIOD = -4.
     */
    public static final int NO_PERIOD = -4;
    /**
     * NO REQUEST TYPE = -1.
     */
    public static final int NO_REQUEST_TYPE = -1;
    /**
     * NO SUPPORT DOCS = -5.
     */
    public static final int NO_SUPPORT_DOCS = -5;
    /**
     * NO RESULT = -8.
     */
    public static final int NO_RESULT = -8;
    /**
     * VALID CODE LENGTH = 6.
     */
    public static final int VALID_CODE_LENGTH = 6;

    /**DAO object to manage Instance objects.
     */
    private InstanceDao instanceDao = new InstanceDao();
    /**DAO object to manage RequestType objects.
     */
    private RequestTypeDao typeDao = new RequestTypeDao();
    /**DAO object to manage Student objects.
     */
    private StudentDao studentDao = new StudentDao();
    /**DAO object to manage Program objects.
     */
    private ProgramDao programDao = new ProgramDao();
    /**DAO object to manage Request objects.
     */
    private RequestDao requestDao = new RequestDao();
    /**EntityManagerFactory created to manage the Persistenc Unit.
     */
    private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("SOLESTACPU");
    /**LogControl object to record events in the log.
     */
    private LogControl log;

    /**Default constructor, creating the log object to record the log events.
     */
    public RequestControl() {
        try {
            log = new LogControl("org.colswe.solestac.control.RequestControl");
        } catch (IOException ex) {
            Logger.getLogger(RequestControl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**Search the active requests by student.
     * @param document Document
     * @return List of RequestVO
     */
    public List<RequestVO> searchPendingByStudent(final String document) {
        List<Student> students;
        List<Request> requests;
        
        List<RequestVO> requestsVO = null;
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        try {
            students = studentDao.searchByIdentification(document, em);
            requests = getPendingRequests(students.get(ALL_GOOD).getRequestList());
            requestsVO = convertRequests(requests);
        } catch (NoResultException ex) {
            requestsVO = new ArrayList<RequestVO>();
        } catch (NonUniqueResultException ex) {
            throw ex;
        } finally {
            em.close();
            return requestsVO;
        }
    }
    
    /**Search all requests by student.
     * @param document Document
     * @return List of RequestVO
     */
    public List<RequestVO> searchByStudent(final String document) {
        List<Student> students;
        List<Request> requests;
        List<RequestVO> requestsVO = new ArrayList<RequestVO>();
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        try {
            students = studentDao.searchByIdentification(document, em);
            requests = students.get(ALL_GOOD).getRequestList();
            requestsVO = convertRequests(requests);
        } catch (NoResultException ex) {
            requestsVO = new ArrayList<RequestVO>();
        } catch (NonUniqueResultException ex) {
            throw ex;
        } finally {
            em.close();
            return requestsVO;
        }
    }

    /**
     * Creates a new request.
     *
     * @param requestVO The Value Object with the information of the new request
     * @param studentVO The Value Object with the information of the user related with the request
     * @return true or false
     */
    public int createRequest(final RequestVO requestVO, final StudentVO studentVO) {
        int result = verifyInfo(requestVO);
        if (result != ALL_GOOD) {
            return result;
        }
        EntityManager em = emf.createEntityManager();
        Request request = convertVO(requestVO, studentVO);
        em.getTransaction().begin();
        try {
            requestDao.create(request, em);
            
            Student student = (studentDao.searchByIdentification(studentVO.getDocument(), em)).get(ALL_GOOD);
            student.getRequestList().add(request);
            studentDao.update(student, em);
                        
            RequestType type = (typeDao.searchByName(requestVO.getRequestType(), em)).get(ALL_GOOD);
            type.getRequestList().add(request);
            typeDao.update(type, em);
            
            Instance instance = (instanceDao.searchByName(requestVO.getInstance(), em)).get(ALL_GOOD);
            instance.getRequestList().add(request);
            instanceDao.update(instance, em);
            
            
            em.getTransaction().commit();
            return ALL_GOOD;
        } catch (NoResultException ex) {
            log.logging(ex);
            return NO_RESULT;
        } catch (NonUniqueResultException ex) {
            log.logging(ex);
            return NO_RESULT;
        } finally {
            em.close();
        }

    }

    /**Create a List<Reuqests_VO> from a List<Request> using the private method convert in a for-each loop.
     * @param requests a List of Request
     * @return a List of RequestVO
     */
    private List<RequestVO> convertRequests(final List<Request> requests) {
        List<RequestVO> requestsVO = new ArrayList<RequestVO>();
        for (Request x : requests) {
            RequestVO requestVO = convert(x);
            requestsVO.add(requestVO);
        }
        return requestsVO;
    }

    /**Creates a RequestVO from a Request data.
     * @param request a Request instance
     * @return a RequestVO
     */
    private RequestVO convert(final Request request) {
        RequestVO requestVO = new RequestVO();
        requestVO.setDate(request.getFilingDate());
        requestVO.setId(request.getId().toString());
        requestVO.setAcademicPeriod(request.getAcademicPeriod());
        requestVO.setInstance(request.getInstanceId().getName());
        requestVO.setDecision(request.getDecision());
        requestVO.setRequestType(request.getTypeId().getName());
        requestVO.setStudentIdentification(request.getStudentId().getDocument());
        requestVO.setProgram(request.getStudentId().getProgramId().getName());
        requestVO.setSupportDocs(request.getSupportdocs());
        return requestVO;
    }

    /**Converts the Value Objects information into a Request object.
     * @param requestVO The RequestVO with the basic info of the request
     * @param studentVO The StudentVo related with the request
     * @return The Request object to Create
     */
    private Request convertVO(final RequestVO requestVO, final StudentVO studentVO) {

        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        Request request = null;
        try {
            request = new Request();
            request.setFilingDate(Date.valueOf(requestVO.getDate().toString()));
            request.setAcademicPeriod(requestVO.getAcademicPeriod());
            request.setDecision(requestVO.getDecision());
            request.setSupportdocs(requestVO.getSupportDocs());
            
            Student student = (studentDao.searchByIdentification(studentVO.getDocument(), em)).get(0);
            request.setStudentId(student);
            
            RequestType type = (typeDao.searchByName(requestVO.getRequestType(), em)).get(0);
            request.setTypeId(type);
            
            Instance instance = (instanceDao.searchByName(requestVO.getInstance(), em)).get(0);
            request.setInstanceId(instance);

        } catch (NoResultException ex) {
            throw ex;
        } catch (NonUniqueResultException ex) {
            throw ex;
        } finally {
            em.close();
            return request;
        }
    }
    
    /**Obtains a list of Requests that are pending.
     * @param requestList a List of Request
     * @return a List of Requests
     */
    private List<Request> getPendingRequests(final List<Request> requestList) {
        List<Request> requests = new ArrayList<Request>();
        for (Request x : requestList) {
            if (x.getInstanceId().getName().equals("En Acta de Consejo")) {
                requests.add(x);
            }
        }
        return requests;
    }
    
    /**Verifies the information contained in the RequestVO object.
     * @param request The requests to be verified.
     * @return  A number indicating the result of the operation.
     */
    public int verifyInfo(final RequestVO request) {
        try {
            if (!(verifyValue(request.getRequestType()))) {
                return NO_REQUEST_TYPE;
            }
            if (!(verifyValue(request.getInstance()))) {
                return NO_INSTANCE;
            }           
            if (!(verifyValue(request.getDecision()))) {
                return NO_DECICION;
            }
            if (!(verifyPeriod(request.getAcademicPeriod()))) {
                return NO_PERIOD;
            }
            if (!(verifySupportDocs(request.getSupportDocs()))) {
                return NO_SUPPORT_DOCS;
            }
            return ALL_GOOD;
        } catch (Exception ex) {
            log.logging(ex);
            return INVALID_PERIOD_NAME;
        }
    }
     
    /**Verifies that the value of the list be different of "Seleccione uno...".
     * @param listValue The string with the selected value in the list.
     * @return true if the listValue is diferent from "Seleccione Uno". false otherwise
     */
    public boolean verifyValue(final String listValue) {
        return (!(listValue.equals("Seleccione uno...")));
    }
    
    /**Verifies the format of the period given.
     * @param period The period given to verify.
     * @return true if the AcademicPeriod have incorrect format. false otherwise
     */
    public boolean verifyPeriod(final String period) {
            if (period.length() == VALID_CODE_LENGTH) {
                if (period.matches("^[0-9]{1,4}\\-[1-3]$")) {
                    return true;
                }               
            }
        return false;
    }
    
    /** Verifies the length of the supportDocs string given.
     * @param supportDocs The string given.
     * @return true if supportDocs doesn't have information. false otherwise
     */
    public boolean verifySupportDocs(final String supportDocs) {
            return (supportDocs.length() != 0);
    }
    
    /**Gets all types of requests in the system.
     * @return  The list of request types found.
     */
    public List<String> getAllRequestTypes() {
        List<String> types = null;
        EntityManager em = emf.createEntityManager();
        try {
            List<RequestType> typeList = typeDao.searchAll(em);
            types = convertTypes(typeList);
        } catch (NoResultException ex) {
            log.logging(ex);
        } finally {
            em.close();
            return types;
        }
    }
    
    /**Gets all instances in the system.
     * @return  The list of instances found
     */
    public List<String> getAllInstances() {
        List<String> instances = null;
        EntityManager em = emf.createEntityManager();
        try {
            List<Instance> instanceList = instanceDao.searchAll(em);
            instances = convertInstances(instanceList);
        } catch (NoResultException ex) {
            log.logging(ex);
        } finally {
            em.close();
            return instances;
        }
    }
    
    /**Gets all decisions in the system.
     * @return  The list of decisions found.
     */
    public List<String> getAllDecisions() {
        List<String> decisions = new ArrayList<String>();
        decisions.add("Aprobada");
        decisions.add("No Aprobada");
        decisions.add("Pendiente");
        decisions.add("Nula");
        return decisions;
    }
    
    /**Converts a list of RequestTYpe objects into a list of String objects.
     * @param typeList The list to be converted.
     * @return The lis of string objects.
     */
    private List<String> convertTypes(final List<RequestType> typeList) {
        List<String> types = new ArrayList<String>();
        for (RequestType type : typeList) {
            String stringType = type.getName();
            types.add(stringType);
        }
        return types;
    }
       
    /**Converts a list of Instance objects into a list of String objects.
     * @param instanceList The list to be converted.
     * @return The lis of string objects.
     */
    private List<String> convertInstances(final List<Instance> instanceList) {
        List<String> instances = new ArrayList<String>();
        for (Instance instance : instanceList) {
            String stringInstance = instance.getName();
            instances.add(stringInstance);
        }
        return instances;
    }
    
    /**Searches requests basen in the parameters given.
     * @param requestVO Value Object with parameters given for requests.
     * @param document Document of student given.
     * @param requestTypes Request Types given like parameter. 
     * @return The requets in the system that matches with the information given.
     */
    public List<RequestVO> searchByFilter(final RequestVO requestVO, final String document, final List<String> requestTypes) {
        List<RequestVO> requestsVO = null;
        List<Request> requests = null;
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();        
        try {
            Long idRequest;            
            if (requestVO.getId().equals("")) { 
                idRequest = 0L;
            } else {
                idRequest = Long.parseLong(requestVO.getId()); 
            }
            
            Long idStudent = getStudentVOId(document, em);
            long[] idTypes = new long[requestTypes.size()];
                for (int i = 0; i < requestTypes.size(); i++) {
                    idTypes[i] = getRequestTypeId(requestTypes.get(i), em);
                }
            
            Long idProgram = getProgramId(requestVO.getProgram(), em);
            Long idInstance = getInstanceId(requestVO.getInstance(), em);
            String academicPeriod = requestVO.getAcademicPeriod();
            
            requests = requestDao.searchByFilter(idRequest, idStudent, idTypes, idProgram, idInstance, academicPeriod, em);
            requestsVO = convertRequests(requests);
            return requestsVO;
        } catch (NoResultException ex) {
            log.logging(ex);
            return null;
        } catch (NonUniqueResultException ex) {
            log.logging(ex);
            return null;
        } finally {
            em.close();
        }
    }

    /**Gets the ID from a student.
     * @param document The documento of the student.
     * @param em THe entity manager to the operation.
     * @return The ID 
     */
    public Long getStudentVOId(final String document, final EntityManager em) {
        try {
            return (studentDao.searchByIdentification(document, em)).get(0).getId();
        } catch (NoResultException ex) {
            return 0L;
        }
    }
    
    /**Gets the ID from a Request Type.
     * @param type The type of the request
     * @param em The entity manager to the operation.
     * @return The ID
     */
    public Long getRequestTypeId(final String type, final EntityManager em) {
        try {
            return (typeDao.searchByName(type, em)).get(0).getId();
        } catch (NoResultException ex) {
            return 0L;
        }
    }
    
    /**Gets the ID from a Program.
     * @param program The document of the student.
     * @param em The entity manager to the operation.
     * @return The ID
     */
    public Long getProgramId(final String program, final EntityManager em) {
        try {
            return (programDao.searchByName(program, em)).get(0).getId();
        } catch (Exception ex) {
            return 0L;
        }
    }
    
    /**Gets the ID from an Instance.
     * @param instance The document of the instance.
     * @param em The entity manager to the operation.
     * @return The ID
     */
    public Long getInstanceId(final String instance, final EntityManager em) {
        try {
            return (instanceDao.searchByName(instance, em)).get(0).getId();
        } catch (NoResultException ex) {
            return 0L;
        }
    }

    /**Verifies the parameters given by the user for a search.
     * @param requestVO Value Object with information of the request given.
     * @param document The document stringn
     * @return  A number indicating the result of the operation.
     */
    public int verifyFilters(final RequestVO requestVO, final String document) {
        if (requestVO.getId().length() > ALL_GOOD) {
            if (Long.parseLong(requestVO.getId()) < ALL_GOOD || Long.parseLong(requestVO.getId()) >= Integer.MAX_VALUE) { 
                return NO_REQUEST_TYPE;
            }
        }
        if (!verifyValue(requestVO.getProgram())) {
            return NO_INSTANCE;
        }
        if (!verifyValue(requestVO.getInstance())) {
            return NO_DECICION;
        }
        StudentControl studentControl = new StudentControl();
        if (!studentControl.verifyDocumentFormat(document)) {
            return NO_PERIOD;
        }
        if (!studentControl.verifyDocumentLength(document)) {
            return NO_SUPPORT_DOCS;
        }
        if (!verifyPeriod(requestVO.getAcademicPeriod())) {
            return INVALID_PERIOD_NAME;
        }
        return ALL_GOOD;
    }

    
    
}
